package tjs.study.notes.dotest.proxy.cglib_eclipse;

import java.lang.reflect.Method;

/**
 * Created by Nicky.Tang on 2021/9/15 10:31 下午
 *
 * @since 02.12.10
 */
public class DoTestOfMyFastClass {
    public static void main(String[] args) throws Throwable {
        UserServiceEnhancer userServiceEnhancer = new UserServiceEnhancer();
        userServiceEnhancer.login();
    }

    static class MethodProxy {
        private FastClassInfo fastClassInfo;

        public MethodProxy(FastClass enhancerFastClass, FastClass targetFastClass, String methdName) {
            /**
             * 为了演示方便，这里直接初始化了
             * 实际上cglib实现是在首次调用MethodProxy.invokeSuper的时候，才调用init方法初始化fastClassInfo
             * @see org.springframework.cglib.proxy.MethodProxy#invokeSuper(Object, Object[])
             */
            FastClassInfo fastClassInfo = new FastClassInfo();
            fastClassInfo.enhancerFastClass = enhancerFastClass;
            fastClassInfo.enhancerMethodIndex = fastClassInfo.enhancerFastClass.getIndex(methdName);
            fastClassInfo.targetFastClass = targetFastClass;
            fastClassInfo.targetMethodIndex = fastClassInfo.targetFastClass.getIndex(methdName);
            this.fastClassInfo = fastClassInfo;
        }

        public Object invoke(Object obj) throws Throwable {
            FastClassInfo fci = fastClassInfo;
            return fci.targetFastClass.invoke(fci.targetMethodIndex, obj);
        }

        public Object invokeSuper(Object obj) throws Throwable {
            FastClassInfo fci = fastClassInfo;
            return fci.enhancerFastClass.invoke(fci.enhancerMethodIndex, obj);
        }

    }

    static abstract class FastClass {
        public abstract int getIndex(String methodName);

        public abstract Object invoke(int methodIndex, Object instance) throws Throwable;
    }

    static class FastClassInfo {
        FastClass enhancerFastClass;//代理类的fastclass
        FastClass targetFastClass;//目标类的fastclass
        int enhancerMethodIndex;//代理方法签名
        int targetMethodIndex;//目标方法签名
    }

    static class UserServiceEnhancerFastClass extends FastClass {

        @Override
        public int getIndex(String methodName) {
            switch (methodName) {
                case "login":
                    return 1;
                case "hashCode":
                    return 2;
            }
            return -1;
        }

        @Override
        public Object invoke(int methodIndex, Object instance) throws Throwable {
            UserServiceEnhancer userServiceEnhancer = (UserServiceEnhancer) instance;
            switch (methodIndex) {
                case 1:
                    return userServiceEnhancer.loginProxy();
                case 2:
                    return userServiceEnhancer.hashCode();
            }
            throw new IllegalArgumentException("Cannot find matching method/constructor");
        }
    }

    static class UserServiceFastClass extends FastClass {

        @Override
        public int getIndex(String methodName) {
            switch (methodName) {
                case "login":
                    return 1;
                case "hashCode":
                    return 2;
            }
            return -1;
        }

        @Override
        public Object invoke(int methodIndex, Object instance) throws Throwable {
            UserService userService = (UserService) instance;
            switch (methodIndex) {
                case 1:
                    return userService.login();
                case 2:
                    return userService.hashCode();
            }
            throw new IllegalArgumentException("Cannot find matching method/constructor");
        }
    }

    static class UserServiceEnhancer extends UserService {
        private UserServiceIntercept userServiceIntercept;
        private static Method targetMethod;
        private static MethodProxy enhancerMethod;

        public UserServiceEnhancer() throws NoSuchMethodException {
            this.userServiceIntercept = new UserServiceIntercept();
        }

        static {
			try {
				targetMethod = UserServiceEnhancer.class.getDeclaredMethod("loginProxy");
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
			enhancerMethod = new MethodProxy(new UserServiceEnhancerFastClass(), new UserServiceFastClass(), "login");
        }

        private Object loginProxy() throws Throwable {
            return super.login();
        }

        @Override
        public Object login() throws Throwable {
            return userServiceIntercept.intercept(this, targetMethod, null, enhancerMethod);
        }
    }

    static class UserServiceIntercept {
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println(method.getName() + "前置增强、、、");
            //Object res = methodProxy.invoke(o);//死循环
            Object res = methodProxy.invokeSuper(o);
            System.out.println(method.getName() + "后置增强、、、");
            return res;
        }
    }

    static class UserService {
        public Object login() throws Throwable {
            System.out.println("登陆中。。。");
            return Boolean.TRUE;
        }
    }
}
